// 函数的length属性是函数期望接收的参数的个数，并不是实际传送的参数。例子如下
// function  foo(a, b) {}
// foo.length 等于 2

// 柯里化个人的理解，其实就是把参数存储起来，直到参数的个数等于要柯里化函数参数的个数，然后执行该函数
// 从而实现参数的复用，比如求一个固定长度的立方体体积，那可以先传入长度

// 如果curry后面的params不用剩余参数，那么初始化的时候，如果传入了多个值，就会导致第一个参数后面的参数全部丢失。
function curry(fn, ...params) {
    let length = fn.length;
    let args = params || [];
    return function (...rest) {
        let _args = [...args, ...rest];
        return _args.length < length
            ? curry.call(this, fn, ..._args)
            : fn.apply(this, _args);
    }
}
function getCapacity(length, width, height) {
    let capacity = length * width * height
    console.log(capacity);
    return capacity
}
const fixedLength = curry(getCapacity, 20)
fixedLength(2, 3)
fixedLength(2)(10)

// 题目，实现一个求和的柯里化函数，要求遇到没有传参就返回和
// currryAdd(1)(2)(3)() currryAdd(1, 2)(3)() curryAdd(1, 2, 3)()
function currryAdd(...params) {
    let sum = params.reduce((pre, cur) => {
        return pre + cur
    }, 0)
    return function(...rest) {
        let _args = [...params, ...rest]
        if(rest.length == 0) return sum
        else {
            return currryAdd.apply(this, _args)
        }
    }
}
console.log(currryAdd(1, 2)());
console.log(currryAdd(1)());
console.log(currryAdd(1)(2)());


function curry(fn, ...args) {
    let length = fn.length
    let params = args || []
    return function(...rest) {
        let _args = [...params, ...rest]
        return _args.length < length ? curry.call(this, fn, ...args) : fn.apply(this, _args)
    }
}